package container

import (
	"os"
	"path/filepath"
	"syscall"
)

// PivotRoot change root dir
func (c *Container) PivotRoot(dir string) error {
	var err error
	dir, err = filepath.Abs(dir)
	if err != nil {
		return err
	}

	putold := filepath.Join(dir, "/.pivot_root")

	if err := syscall.Mount(dir, dir, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return err
	}

	if err := os.MkdirAll(putold, 0700); err != nil {
		return err
	}
	defer os.RemoveAll(putold)

	if err := syscall.PivotRoot(dir, putold); err != nil {
		return err
	}

	if err := os.Chdir("/"); err != nil {
		return err
	}

	putold = "/.pivot_root"
	return syscall.Unmount(putold, syscall.MNT_DETACH)
}

func (c *Container) initMount() error {
	err := mount("/proc", "proc", "", 0555, syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV)
	if err != nil {
		return err
	}
	err = mount("/dev", "tmpfs", "mode=755", 0755, syscall.MS_NOSUID|syscall.MS_STRICTATIME)
	if err != nil {
		syscall.Unmount("proc", 0)
		return err
	}
	err = mount("/sys", "sysfs", "", 0555, syscall.MS_NOSUID|syscall.MS_NODEV|syscall.MS_NOEXEC|syscall.MS_RELATIME)
	if err != nil {
		syscall.Unmount("proc", 0)
		syscall.Unmount("tmpfs", 0)
		return err
	}
	err = mount("/dev/pts", "devpts", "mode=620,ptmxmode=666,gid=5", 0620, syscall.MS_NOSUID|syscall.MS_NOEXEC|syscall.MS_RELATIME)
	if err != nil {
		syscall.Unmount("proc", 0)
		syscall.Unmount("tmpfs", 0)
		syscall.Unmount("sysfs", 0)
		return err
	}
	return nil
}

// Close close container
func (c *Container) Close() error {
	syscall.Unmount("proc", 0)
	syscall.Unmount("tmpfs", 0)
	syscall.Unmount("sysfs", 0)
	syscall.Unmount("devpts", 0)
	return nil
}

func mount(dir, class, ext string, perm os.FileMode, flag uintptr) error {
	os.RemoveAll(dir)
	if err := os.MkdirAll(dir, perm); err != nil {
		return err
	}
	return syscall.Mount(class, dir, class, flag, ext)
}
